package com.apps.java.javanote02;

import com.sun.jdi.PathSearchingVirtualMachine;

import javax.net.ssl.SSLServerSocket;
import javax.sound.midi.Soundbank;
import java.time.Year;
import java.util.ArrayList;

public class _26Lambda表达式 {
    /**
     * Lambda
     *  一、函数式编程思想概述
     *      在数学中，函数就是有输入量、输出量的一套计算方案，也就是“拿数据做操作”
     *      面向对象思想强调“必须通过对象的形式来做事情”
     *      函数式思想则尽量忽略面向对象的复杂语法：“强调做什么，而不是以什么形式去做”
     *
     *  二、Lambda表达式的标准格式
     *      1.匿名内部类中重写run()方法的代码分析
     *          @Override
     *      new Thread(new Runnable(){
     *      *          public void run(){
     *              syso("多线程启动");
     *          }
     *      }).start();
     *          1.方法形式参数为空，说明调用方法时不需要传递参数
     *          2.方法返回值类型为void，说明反方执行没有结果返回
     *          3.方法体中的内容，是我们具体要做的事情
     *
     *      2.Lambda表达式的代码分析
     *      new Thread(() -> {
     *          syso("多线程启动");
     *      }).start();
     *          1.()：里面没有内容，可以看成是方法形式参数为空
     *          2.->：用箭头指向后面要做的事情
     *          3.{}：包含一段代码，我们称之为代码块，可以看成是方法体中的内容
     *      3.组成Lambda表达式的三要素：形式参数、箭头、代码块
     *      4.Lambda表达式的使用前提：有一个接口，接口中有且只有一个抽象方法
     *      5.Lambda表达式的格式
     *          (形式参数) -> {代码块}
     *          1.形式参数：如果有多个参数，参数之间用逗号隔开；如果没有参数，留空即可
     *          2.->：由英文中画线和大于符号组成，固定写法，代表指向动作
     *          3.代码块：使我们具体要做的事情，也就是以前我们写的方法体内容
     *
     *  三、Lambda表达式的省略模式
     *      省略规则
     *          1.参数类型可以省略，但是有多个参数的情况下，不能只省略一个
     *          2.如果参数有且只有一个，那么小括号可以省略
     *          3.如果代码块的语句只有一条，可以省略大括号和分号，return也要省略
     *
     *  四、Lambda表达式的注意事项
     *      注意事项：
     *          1.使用Lambda必须要有接口，并且要求接口中有且仅有一个抽象方法
     *          2.必须要有上下文环境，才能推导出Lambda对应的接口
     *              根据局部变量的赋值得知Lambda对应的接口：Runnable r = () -> syso("Lambda表达式");
     *              根据调用方法的参数得知Lambda对应的接口：new Thread(() -> syso("Lambda表达式")).start();
     *
     *  五、Lambda表达式和匿名内部类的区别
     *      1.所需类型不同
     *          .匿名内部类：可以是接口，也可以是抽象类，还可以是具体类
     *          .Lambda表达式：只能是接口
     *      2.使用限制不同
     *          .如果接口中有且仅有一个抽象方法，可以使用Lambda表达式，也可以使用匿名内部类
     *          .如果接口中多于一个抽象方法，只能使用匿名内部类，而不能使用Lambda表达式
     *      3.实现原理不同
     *          .匿名内部类：编译之后，产生了一个单独的.class字节码文件
     *          .Lambda表达式：编译之后，没有一个单独的.class字节码文件。对应的字节码会在运行的时候动态产生。
     *
     */

    public static void main(String[] args) {
        //实现类的方式实现多线程
//		MyRunnable my = new MyRunnable();
//		Thread t = new Thread();
//		t.start();

        //采用匿名内部类的方式改进
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("多线程启动");
            }
        }).start();

        //Lambda表达式的方式改进
        new Thread(() -> {
            System.out.println("多线程启动了");
        }).start();

        //Lambda参数类型可省略：但是有多个参数的情况下，不能只省略其中一个
        useNum((x, y) -> {
            return x + y;
        });
        //如果参数有且只有一个，那么小括号也可以省略
        /*
            useString(s -> {
                syso(s);
            });
         */
        //如果代码块的语句只有一条可以省略大括号和分号，如果有return，return也要省略掉
        useNum((x,y) -> x+y );
        /*
            useString(s -> syso(s));
         */

    }

    public static void useNum(Num n) {
        int num = n.getNum(10, 20);
        System.out.println(num);
    }
    public static void useNum2(Num n) {
        int num = n.getNum(30, 20);
        System.out.println(num);
    }
}
